import { merge, transform } from 'lodash-es';

interface Model {
  modelId: string;
  name?: string;
}

interface ComposedModel<T extends Model> {
  modelId: string;
  /** += models[i].name */
  name?: string;
  models: T[];
}

export function composeModels<T extends Model>(
  models: T[],
): ComposedModel<T>[] {
  const separator = ' | ';
  return transform(
    models,
    ({ composedModels, composedModelRecord }, model) => {
      const { modelId, name } = model;
      const composedModel = composedModelRecord[modelId];
      if (!composedModel) {
        const composedModel = {
          modelId,
          name,
          models: [model],
        };

        composedModelRecord[modelId] = composedModel;
        composedModels.push(composedModel);
        return;
      }
      composeField(composedModel, 'name', name, separator);
      composedModel.models.push(model);
    },
    {
      composedModels: [] as ComposedModel<T>[],
      composedModelRecord: {} as Record<string, ComposedModel<T>>,
    },
  ).composedModels;
}

/** data[field] += value */
function composeField(data: any, field: string, value: any, separator = ',') {
  return data[field] && (data[field] += separator + value);
}

export function genModelId<T extends Model>(
  model: Omit<T, 'modelId'> & Partial<Pick<T, 'modelId'>>,
) {
  return merge(model, {
    modelId: model.modelId || 'undefined',
  });
}

export function excludeModel<T extends Pick<Model, 'name'>>(
  model: T,
  excludeModelNames: string[],
) {
  if (!model.name) {
    return true;
  }
  return !excludeModelNames.includes(model.name);
}
